<!DOCTYPE html>
<html>
  <head>
    <title>设计模式培训之二</title>

    <meta charset='utf-8'>
    <script
      src='../slider/slides.js'></script>
  </head>
  
  <style>

  </style>

  <body style='display: none'>

    <section class='slides layout-regular template-default'>
      <!-- 第一页 -->
      <article>
      	<h1 style="text-align:center">设计模式系列之二</h1>
      	<br />
      	<h2 style="text-align:right">基础研发部——姜纯洋（@终小南）</h2>
      </article>

	<!-- 第二页 -->
	<article>
		<h3>目录</h3>
		<ul class="build">
			<li><h4>讲座简介</h4></li>
			<li><h4>往期回顾</h4></li>
			<li><h4>装饰器模式</h4></li>
			<li><h4>外观模式</h4></li>
		</ul>
	</article>
    
    <!--第三页-->
    <article>
    	<ul class="build">
        	<li>
            <h3>小明的麻烦</h3>
            《微三国》游戏项目组的程序员小明收到一个需求，给每一个武将增加一个睡觉的功能，一旦武将启用睡觉功能，则其带兵上限、攻击力、防御力都会有所提升。</li>
            <li>
            	<h3>小明的解决方法</h3>
            作为一个专业学过设计模式并且具有良好开发习惯的小明知道：武将的基础代码不能修改！于是小明决定————继承。即写一个武将子类，在子类中给武将增加睡觉的功能。小明太有才了！
            </li>
            <li>
            	<h3>小明的新问题</h3>
        	还是上边的小明，又收到了一个需求：给每一个武将增加一个吃饭的功能，武将启用吃饭功能的时候存在一定的几率使其获得某些技能或者带来技能槽的扩展。
            </li>
            <li>
            	<h3>小明的沉思</h3>
                因为刚刚实现了睡觉这个类似的功能，小明立马想到了可以用继承的方式来实现这个需求，但是作为一个有着丰富开发经验的工程师，小明也同时想到了，这个需求里，武将肯定是既要有吃饭的功能也要有睡觉的功能，所以新的类将要从原来那个有睡觉功能的武将子类进行继承。
            </li>
            <li>
            <h3>但是</h3>
            小明似乎也想到了一个更新的问题：以后会不会有其它更多的功能要添加进来呢？那么这个继承需要有多深呢？小明陷入了沉思。
            </li>
        </ul>
    </article>
    
    <!--第七页-->
    <article>
    	<h3>曙光</h3>
        <ul class="build">
        	<li>装饰器模式：采用对象组合而非继承的手法，实现了在运行时动态的扩展对象功能的能力，而且可以根据需要扩展多个功能，避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。同时它很好地符合面向对象设计原则中“优先使用对象组合而非继承”和“开放-封闭”原则。
            </li>
        </ul>
    </article>
    <!--第八页-->
    <article>
    	<h3>装饰器模式</h3>
        <ul class="build">
        	<li>
        	<img src="images/装饰器模式-武将.png" />
            </li>
        </ul>
    </article>
    <!--第九页-->
    <article>
    	<h3>用代码说话</h3>
        <ul class="build">
        	<li>
            	抽像武将类
                <pre>
abstract class IGeneral{
	public function attack(){}
}
                </pre>
            </li>
            <li>
            具体武将类
         	<pre>
class General extends IGeneral{
	public function attack(){
		echo '战斗&lt;br/&gt;';
	}
}
            </pre>
            </li>
        </ul>
    </article>
    <!--第十页-->
    <article>
    	<h3>用代码说话</h3>
        <ul class="build">
        	<li>
            	抽像装饰器
                <pre>
class Decorator extends IGeneral{
	protected $_general;
	public function __construct($general){
		$this->_general = $general;
	}

	public function __call($func, $params){
		$this->_general->$func($params);
	}
}
                </pre>
            </li>
        </ul>
    </article>

    <!--第十一页-->
    <article class="smaller">
    	<h3>用代码说话</h3>
        <ul class="build">
        	<li>
            	睡觉
                <pre>
class SleepDecorator extends Decorator{
	public function attack(){
		echo '有睡觉功能|';
		$this->_general->attack();
	}
	
	public function sleep(){
		echo '睡觉&lt;br/&gt;';
	}
}
                </pre>
            </li>
            <li>
            	吃饭
                <pre>
class EatDecorator extends Decorator{
	public function attack(){
		echo '有吃饭功能|';
		$this->_general->attack();
	}
	
	public function eat(){
		echo '吃饭&lt;br/&gt;';
	}
}
                </pre>
            </li>
        </ul>
    </article>    
    <!--第十二页-->
    <article>
    	<h3>演示</h3>
        <ul class="build">
        	<li>
            	<pre>
$general = new General();
$general->attack();</pre>
                <a href="/decorator3/demo/demo.php" target="decorator-demo">效果</a>            </li>
            <li>
            	<pre>
$sleepDecorator = new SleepDecorator($general);
$sleepDecorator->attack();
$sleepDecorator->sleep();</pre>
                <a href="/decorator3/demo/demo.php?step=2" target="decorator-demo">效果</a>            </li>
            <li>
            	<pre>
$eatDecorator = new EatDecorator($sleepDecorator);
$eatDecorator->attack();
$eatDecorator->sleep();
$eatDecorator->eat();</pre>
                <a href="/decorator3/demo/demo.php?step=3" target="decorator-demo">效果</a>            </li>
            <li>
            	<pre>
$general = new EatDecorator( new SleepDecorator( new General() ) );
$general->attack();
$general->sleep();
$general->eat();
                </pre>
                <a href="/decorator3/demo/demo.php?step=4" target="decorator-demo">效果</a>            </li>
        </ul>
    </article>
    <!--第十三页-->
    <article>
    	<h3>
        	特点总结：        </h3>
        <ul class="build">
        	<li>要解决的问题：
            	<ul class="build">
                	<li>面向对象开发的开放—封闭原则：即对象对扩展是开放的，对修改是封闭的。</li>
                    <li>类扩展时单纯的使用子类导致的继承爆炸，以及继承不灵活的特点。</li>
                    <li>动态的为对象添加或者删除一些方法或属性。</li>
                </ul>
            </li>
            <li>
            	适应的场合：
                <ul class="build">
                	<li>当我们需要扩展一个类又不想对这个类进行修改时。</li>
                    <li>当我们需要对一个类动态添加一些功能又需要动态删除这些功能时。</li>
                    <li>当我们需要增加由一些基本功能的排列组合而产生的非常大量的功能，从而使继承关系变得不现实。</li>
                </ul>
            </li>
        </ul>
    </article>
    <!--第十四页-->
    <article>
    	<h3>是不是太复杂了？</h3>
        <ul class="build">
        	<li>比如刚才的例子，我们只有一个基本的武将类，这种情况下，我们可以把抽象的装饰器类精简掉，而直接让装饰类继承于基础的武将类。</li>
            <li><img src="images/装饰器模式-武将(精简).png" /></li>
        </ul>
    </article>
    <!--第十五页-->
    <article>
    	<h3>现在去重构你的项目</h3>
        <ul class="build">
        	<li>对于一个陈旧的项目，以前只有mysql的操作需求，现在要求你增加memcache、redis缓存，你怎么办？</li>
            <li>已经写好的项目，比如微博，由于平台种类的增多，要求服务器端返回不同格式的数据，json/xml/base64/html/wap/txt/excel等等。怎么处理？</li>
            <li>博客系统中，如果需要验证用户填写博文的合法性，比如长度是不是符合要求，比如是否含有图片等。</li>
            <li>其它需要对原来项目进行动态扩展的需求。</li>
        </ul>
    </article>
    <!--第十六页-->
    <article>
        <ul class="build">
        	<li>
            <h3>小明的麻烦</h3>
            小明是公司博客项目组的工程师，因为2012奥运会开赛在即，需要博客系统给一些相关专题网站提供一些接口，需求的接口有：博文列表接口、博文显示接口、博文评论列表接口、博文转发列表接口、相关博文接口、博文访客列表接口。
            </li>
            <li>
            <h3>小明的解决方案</h3>
            为响应公司平台化的倡议，小明决定把上边这几个接口直接开放给用户供用户使用。
            </li>
            <li>
            <h3>小明的新烦恼</h3>
            博客项目组为了适应新的需求，决定把博文评论和转发功能进行调整，这样小明在读取到博文评论信息的时候就同时可以获得转发信息，加上用户为了获得以上信息因为要进行多次远程请求导致页面打开速度很慢，同时也给博客服务器带来了很大的压力。而且博客研发组给的回复是以后博客还有可能进行再次的升级。为了保证需求方项目的稳定，小明怎么办？
            </li>
        </ul>
    </article>
    <!--第十七页-->
    <article>
    	<h3>外观模式</h3>
        <ul class="build">
        	<li>
            	<h4>定义</h4>
            	它为子系统中的一组接口提供一个统一的高层接口。使用子系统更容易使用。
            </li>
            <li>
            	<h4>没有加入高层接口</h4>
                <img src="images/外观模式（无外观）.png" />
            </li>
            <li>
            	<h4>外观模式</h4>
                <img src="images/外观模式.png" />
            </li>
        </ul>
    </article>
    <!--第十八页-->
    <article>
    	<h3>用代码说话</h3>
        <ul class="build">
        	<li>
            	<h4>博客类</h4>
                <pre>
class Blog{
	public function get($count){
		echo str_repeat('一条博文&lt;br/&gt;', $count);
	}
}
                </pre>
            </li>
            <li>
            <h4>评论类</h4>
            <pre>
class Comment{
	public function get($count){
		echo str_repeat('一条评论&lt;br/&gt;', $count);
	}
}
			</pre>
            </li>
            <li>
           	<h4>访客类</h4>
            <pre>
class Visitor{
	public function get($count){
		echo str_repeat('一条访客记录&lt;br/&gt;', $count);
	}
}
            </pre>
            </li>
        </ul>
    </article>
    <!--第十九页-->
    <article>
    	<h3>
        	无聊的演示
        </h3>
        <ul class="build">
        	<li>
            <pre>
$blog = new Blog();
$blog->get(10);

$comment = new Comment();
$comment->get(5);

$visitor = new Visitor();
$visitor->get(8);
            </pre>
            </li>
            <li>
            <a href="/facade/demo/demo.php?step=1" target="facade-demo">演示</a>
            </li>
        </ul>
    </article>
    <!--第二十页-->
    <article class="smaller">
    	<h3>使用外观模式</h3>
        <ul class="build">
        	<li>
            	<h4>外观类</h4>
                <pre>
class Facade{
	private $_blog;
	private $_comment;
	private $_visitor;
	public function __construct(){
		$this->_blog = new Blog();
		$this->_comment = new Comment();
		$this->_visitor = new Visitor();
	}
	public function get($params){
		$this->_blog->get($params['blog']);
		$this->_comment->get($params['comment']);
		$this->_visitor->get($params['visitor']);
	}
}
                </pre>
            </li>
            <li>
            	<pre>
$facade = new Facade();
$params = array(
	'blog'	=> 10,
	'comment'	=> 5,
	'visitor'	=> 8,
);
$facade->get($params);
                </pre>
            </li>
            <li>
            <a href="/facade/demo/demo.php?step=2" target="facade-demo">演示</a>
            </li>
        </ul>
    </article>
    <!--第二十一页-->
    <article>
    	<h3>看起来没那么神奇？</h3>
        <ul class="build">
        	<li>当接口都是远程调用的时候：减少远程连接的次数。</li>
            <li>当底层接口有不断变化的需求的时候：保证了接口的稳定性。</li>
            <li>当一次完整调用涉及到很多子模块的时候：屏蔽了子模块的实现细节，简化了调用的代码。</li>
        </ul>
    </article>
    <!--第二十二页-->
    <article>
    	<h3>我好像没有接触过它？</h3>
        <ul class="build">
        	<li>
            在使用MVC架构进行开发的时候，每一次加载模板文件的时候，你会考虑模板文件不存在时怎么提示，模板目录修改对我们的操作所产生的影响吗？
            </li>
            <li>
            为了联接数据库，你会每次都经历mysql_connect,mysql_select_db,mysql_set_charset,mysql_query,mysql_fetch这个过程吗？
            </li>
            <li>
            对于一些经常被复用的需要涉及多个子模块的复杂的业务逻辑，你是选择把它们提取出来放在一个公共的Business类里还是每次都依次去调用它的子模块？
            </li>
        </ul>
    </article>
    <!--第二十三页-->
    <article>
    	<h3>似曾相识？</h3>
        <ul class="build">
        	<li>
            <h4>与抽象工厂</h4>
            外观模式可以用来以一种子系统独立的方式创建子系统对象，抽像工厂模式可以代替外观模式用来屏蔽那些与平台相关的类。</li>
            <li>
            <h4>与中介者</h4>
            共同点：二者都是抽像了一些已有类的功能。但是，中介者的目的是对同事类之间的任意通讯进行抽象，通常集中不属于任何单个对象的功能。中介者模式的同事类知道中介者，并与之进行通信，而拒绝与其它同类进行通信。相对而言，外观模式仅对子系统对象的接口进行抽象，从而使它们更容易使用，它并不定义新功能，子系统也不知道facade的存在。
            </li>
            <li>
            <h4>与单例模式</h4>
            一般来说，我们只有一个facade，所以它通常是属于单例的。
            </li>
        </ul>
    </article>
    <!--第二十四页-->
    <article>
    	<ul class="build">
        <li>
    	<h3>参考资料</h3>
        <ul>
        	<li>大话设计模式</li>
            <li>设计模式——机械工业出版社</li>
            <li>各搜索引擎</li>
        </ul>
        </li>
        <li>
        <h3>交流</h3>
        <ul>
        	<li>个人博客：http://blog.mrjiang.com</li>
            <li>微博：@终小南</li>
            <li>演示代码及PPT：http://patterndemo.sinaapp.com</li>
        </ul>
        </li>
        </ul>
    </article>
    <!--第二十五页-->
    <article>
    	<h1 style="text-align:center">谢谢！</h1>
    </article>
    <!--第二十六页-->
    <!--第二十七页-->
    <!--第二十八页-->
    <!--第二十九页-->
    <!--第三十页-->
    <!--第三十一页-->
    <!--第三十二页-->
    <!--第三十三页-->
    <!--第三十四页-->
    </section>

  </body>
</html>
